//
//  EvolutionaryController.h
//  symbrion
//
//  Created by Berend Weel on 4/15/13.
//  Copyright (c) 2013 Berend Weel. All rights reserved.
//

#ifndef symbrion_EvolutionaryController_h
#define symbrion_EvolutionaryController_h

#include <boost/ptr_container/ptr_deque.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include "Controller.h"
#include "RobotType.h"

#include "News.h"
#include "Individual.h"

#include "EAController.h"
#include "FitnessMeasure.h"

#define POPULATION_SIZE 15  // Size of the population
#define FREE_TIME 4         // Fitness free time in seconds
#define EVALUATION_TIME 56  // Evalution time in seconds
#define MAX_CACHE_SIZE 25   // Maximum cache size
#define CROSSOVERRATE 0.1   // The crossover rate

class EvolutionaryController : public Controller {
public:
    EvolutionaryController(WorldModel *worldModel, RobotType *robot, EAController *controller);
    virtual ~EvolutionaryController();
    virtual void step();
   
private:
    void initialiseEvolution();
    void startEvaluation();
    
    Individual *getNextCandidate();
    Individual *uniformSelection();
    
    void uniformCrossOver(Individual *next,Individual *father,Individual *mother);
    void gaussianMutation(Individual *next);
    
    void setNews(News *news);
    void exchangeCaches();
    void receiveCaches();
       
    // Current state
    enum State {initialising, free, evaluating} state;
    bool initialEvaluation;
    
    // Current generation
    unsigned int generation;
    unsigned int evaluations;
    
    // Fitness measurment
    FitnessMeasure *fitnessMeasure;
    
    // Timing
    LIOReal startTime;
    
    // Current individual
    Individual *candidate;
    
    // Best individual
    Individual best;
    
    // The controller
    EAController *controller;
    
    // The WorldModel
    WorldModel *worldModel;
    
    // The population
    boost::ptr_deque<Individual> population;
    
    // The news cache
    boost::ptr_deque<News> cache;
    
    static bool hasNoFitness(const Individual &individual) {
        return !individual.hasFitness;
    }
};

#endif
